<template>
  <div ref="elRef">
    <div style="float: left; padding-top: 40px; width: 280px">
      <div>
        <span>aspect:</span>
        <input type="range" v-model="aspect" max="2" step="0.05" min="0.1" />{{
          aspect
        }}
      </div>
      <div>
        使用透射相机：<input type="checkbox" v-model="usePerspective" />
      </div>
      <template v-if="usePerspective">
        <div>
          <span>fov:</span>
          <input type="range" v-model="persConfig.fov" max="179" min="10" />{{
            persConfig.fov
          }}
        </div>
        <div>
          <span>near:</span>
          <input type="range" v-model="persConfig.near" max="9900" />{{
            persConfig.near
          }}
        </div>
        <div>
          <span>far:</span>
          <input type="range" v-model="persConfig.far" max="9900" />{{
            persConfig.far
          }}
        </div>
        <div>
          x:
          <input type="range" v-model="persConfig.x" step="10" max="5000" />{{
            persConfig.x
          }}
        </div>
        <div>
          y:
          <input type="range" v-model="persConfig.y" step="10" max="5000" />{{
            persConfig.y
          }}
        </div>
        <div>
          z:
          <input type="range" v-model="persConfig.z" step="10" max="5000" />{{
            persConfig.z
          }}
        </div>
      </template>
      <template v-else>
        <div>
          half-h:
          <input
            type="range"
            v-model="orthoConfig.hh"
            step="10"
            min="1"
            max="2500"
          />{{ orthoConfig.hh }}
        </div>
        <div>
          near:
          <input type="range" v-model="orthoConfig.n" step="10" max="5000" />{{
            orthoConfig.n
          }}
        </div>
        <div>
          far:
          <input type="range" v-model="orthoConfig.f" step="10" max="5000" />{{
            orthoConfig.f
          }}
        </div>
        <br />
        <div>
          x:
          <input type="range" v-model="orthoConfig.x" step="10" max="5000" />{{
            orthoConfig.x
          }}
        </div>
        <div>
          y:
          <input type="range" v-model="orthoConfig.y" step="10" max="5000" />{{
            orthoConfig.y
          }}
        </div>
        <div>
          z:
          <input type="range" v-model="orthoConfig.z" step="10" max="5000" />{{
            orthoConfig.z
          }}
        </div>
      </template>
    </div>
  </div>
</template>

<script setup>
import {
  Scene,
  WebGLRenderer,
  PerspectiveCamera,
  OrthographicCamera,
  Mesh,
  BoxGeometry,
  MeshLambertMaterial,
  PointLight,
  AmbientLight,
  AxesHelper,
  Group,
} from "three";

import { ref, onMounted, reactive } from "vue";

/**@type {import('vue').Ref<HTMLDivElement>} */
const elRef = ref(null);
const usePerspective = ref(true);
const aspect = ref(1);
const W = 800;
const H = 800;
const renderer = new WebGLRenderer();
renderer.setSize(W, H);
renderer.setClearColor(0xb9d3ff, 1);

const persConfig = reactive({
  fov: 60,
  x: 200,
  y: 300,
  z: 200,
  near: 1,
  far: 2000,
});

const orthoConfig = reactive({
  hh: 1000,

  n: 1,
  f: 2000,
  x: 200,
  y: 200,
  z: 300,
});

const scene = new Scene();
scene.add(new AxesHelper(H * 100));

let group = new Group();
let N = 2; // 8*N^3
let size = 200;
let gap = size * 2.5; // (2*N*2.5+1)*size/2 = (5N+1)* size/2  // 1100
for (let i = -N; i <= N; i++) {
  for (let j = -N; j <= N; j++) {
    for (let k = -N; k <= N; k++) {
      var mesh = new Mesh(
        new BoxGeometry(size, size, size),
        new MeshLambertMaterial({
          color: "#" + Math.random().toString(16).substring(2, 8),
        })
      );

      mesh.position.set(gap * i, gap * j, gap * k);
      group.add(mesh);
    }
  }
}
scene.add(group);

var point = new PointLight(0xffffff);
point.position.set(400, 300, 350); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new AmbientLight(0x444444);
scene.add(ambient);
const orthographicCamera = new OrthographicCamera();
const perspectiveCamera = new PerspectiveCamera();

onMounted(() => {
  elRef.value.appendChild(renderer.domElement);

  const renderFn = () => {
    const asp = (aspect.value * W) / H;
    if (usePerspective.value) {
      perspectiveCamera.position.set(
        +persConfig.x,
        +persConfig.y,
        +persConfig.z
      ); //设置相机位置
      perspectiveCamera.fov = +persConfig.fov;
      perspectiveCamera.aspect = asp;
      perspectiveCamera.near = +persConfig.near;
      perspectiveCamera.far = +persConfig.far;
      perspectiveCamera.lookAt(scene.position); //设置相机方向(指向的场景对象)
      perspectiveCamera.updateProjectionMatrix();
    } else {
      orthographicCamera.position.set(
        orthoConfig.x,
        orthoConfig.y,
        orthoConfig.z
      );
      orthographicCamera.left = -orthoConfig.hh * asp;
      orthographicCamera.right = +orthoConfig.hh * asp;
      orthographicCamera.top = +orthoConfig.hh;
      orthographicCamera.bottom = -orthoConfig.hh;

      orthographicCamera.near = +orthoConfig.n;
      orthographicCamera.far = +orthoConfig.f;

      orthographicCamera.lookAt(scene.position);
      orthographicCamera.updateProjectionMatrix();
    }
    const camera = usePerspective.value
      ? perspectiveCamera
      : orthographicCamera;
    renderer.render(scene, camera);
    requestAnimationFrame(renderFn);
  };
  renderFn();
});
</script>

<style>
</style>